"""
安全工具函数
包括密码哈希、JWT Token生成和验证
"""
from datetime import datetime, timedelta
from typing import Optional, Any
from jose import JWTError, jwt
from passlib.context import CryptContext

from app.config import settings


# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


# ==================== 密码处理 ====================

def hash_password(password: str) -> str:
    """
    密码哈希加密
    
    Args:
        password: 明文密码
        
    Returns:
        加密后的密码哈希
    """
    return pwd_context.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证密码
    
    Args:
        plain_password: 明文密码
        hashed_password: 哈希密码
        
    Returns:
        密码是否匹配
    """
    return pwd_context.verify(plain_password, hashed_password)


# ==================== JWT Token ====================

def create_access_token(
    data: dict,
    expires_delta: Optional[timedelta] = None
) -> str:
    """
    创建访问令牌
    
    Args:
        data: 要编码的数据
        expires_delta: 过期时间增量
        
    Returns:
        JWT token字符串
    """
    to_encode = data.copy()
    
    # 设置过期时间
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(
            minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES
        )
    
    to_encode.update({
        "exp": expire,
        "iat": datetime.utcnow(),
        "type": "access"
    })
    
    # 生成token
    encoded_jwt = jwt.encode(
        to_encode,
        settings.JWT_SECRET_KEY,
        algorithm=settings.JWT_ALGORITHM
    )
    
    return encoded_jwt


def create_refresh_token(
    data: dict,
    expires_delta: Optional[timedelta] = None
) -> str:
    """
    创建刷新令牌
    
    Args:
        data: 要编码的数据
        expires_delta: 过期时间增量
        
    Returns:
        JWT refresh token字符串
    """
    to_encode = data.copy()
    
    # 设置过期时间（更长）
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(
            days=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS
        )
    
    to_encode.update({
        "exp": expire,
        "iat": datetime.utcnow(),
        "type": "refresh"
    })
    
    # 生成token
    encoded_jwt = jwt.encode(
        to_encode,
        settings.JWT_SECRET_KEY,
        algorithm=settings.JWT_ALGORITHM
    )
    
    return encoded_jwt


def decode_token(token: str) -> Optional[dict]:
    """
    解码JWT token
    
    Args:
        token: JWT token字符串
        
    Returns:
        解码后的数据字典，失败返回None
    """
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            algorithms=[settings.JWT_ALGORITHM]
        )
        return payload
    except JWTError as e:
        # 添加详细日志
        from loguru import logger
        logger.error(f"Token解码失败: {type(e).__name__}: {str(e)}")
        logger.error(f"Token (前50字符): {token[:50]}...")
        logger.error(f"JWT_SECRET_KEY (前20字符): {settings.JWT_SECRET_KEY[:20]}...")
        logger.error(f"JWT_ALGORITHM: {settings.JWT_ALGORITHM}")
        return None


def verify_token(token: str) -> bool:
    """
    验证token是否有效
    
    Args:
        token: JWT token字符串
        
    Returns:
        token是否有效
    """
    payload = decode_token(token)
    return payload is not None


def get_token_payload(token: str) -> Optional[dict]:
    """
    获取token载荷数据
    
    Args:
        token: JWT token字符串
        
    Returns:
        token中的数据
    """
    return decode_token(token)


def extract_user_id_from_token(token: str) -> Optional[int]:
    """
    从token中提取用户ID
    
    Args:
        token: JWT token字符串
        
    Returns:
        用户ID
    """
    payload = decode_token(token)
    if payload:
        return payload.get("sub")
    return None


# ==================== API Key生成 ====================

import secrets
import hashlib


def generate_api_key() -> str:
    """
    生成API密钥
    
    Returns:
        32位随机字符串
    """
    return secrets.token_urlsafe(32)


def generate_session_id() -> str:
    """
    生成会话ID
    
    Returns:
        会话ID
    """
    return secrets.token_urlsafe(16)


def generate_order_no() -> str:
    """
    生成订单号
    
    Returns:
        订单号（时间戳 + 随机数）
    """
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    random_part = secrets.token_hex(4).upper()
    return f"ORD{timestamp}{random_part}"


def hash_string(text: str) -> str:
    """
    哈希字符串（SHA256）
    
    Args:
        text: 要哈希的文本
        
    Returns:
        哈希值
    """
    return hashlib.sha256(text.encode()).hexdigest()


# ==================== 输入验证和清理 ====================

import re


def sanitize_input(text: str) -> str:
    """
    清理用户输入，防止XSS等攻击
    
    Args:
        text: 用户输入文本
        
    Returns:
        清理后的文本
    """
    # 移除HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    # 移除特殊字符
    text = re.sub(r'[<>\"\'&]', '', text)
    return text.strip()


def is_valid_email(email: str) -> bool:
    """
    验证邮箱格式
    
    Args:
        email: 邮箱地址
        
    Returns:
        是否有效
    """
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email) is not None


def is_valid_phone(phone: str) -> bool:
    """
    验证手机号格式（中国）
    
    Args:
        phone: 手机号
        
    Returns:
        是否有效
    """
    pattern = r'^1[3-9]\d{9}$'
    return re.match(pattern, phone) is not None


def is_strong_password(password: str) -> tuple[bool, str]:
    """
    检查密码强度
    
    Args:
        password: 密码
        
    Returns:
        (是否符合要求, 错误信息)
    """
    if len(password) < 8:
        return False, "密码长度至少为8位"
    
    if len(password) > 32:
        return False, "密码长度不能超过32位"
    
    if not re.search(r'[a-z]', password):
        return False, "密码必须包含小写字母"
    
    if not re.search(r'[A-Z]', password):
        return False, "密码必须包含大写字母"
    
    if not re.search(r'\d', password):
        return False, "密码必须包含数字"
    
    return True, ""







